////////////////////////////////////////////////////////////////////////////////

#include "server_network.h"

////////////////////////////////////////////////////////////////////////////////


ServerNetwork::ServerNetwork( ClientPackets& _recvQueue,
                              ServerPackets& _sendQueue,
                              Mutex& _sendQueueMutex,
                              Mutex& _recvQueueMutex,
                              const std::string& _sendPort,
                              const std::string& _recvPort )
: m_RecvQueue(_recvQueue),
  m_SendQueue(_sendQueue),
  m_RecvQueueMutex(_recvQueueMutex),
  m_SendQueueMutex(_sendQueueMutex),
  m_StartThread(NULL),
  m_SendPort(_sendPort),
  m_RecvPort(_recvPort)
{
}


////////////////////////////////////////////////////////////////////////////////


ServerNetwork::~ServerNetwork()
{
    if (m_StartThread)
        delete m_StartThread;
}


////////////////////////////////////////////////////////////////////////////////


void ServerNetwork::Start()
{
    if (!m_StartThread)
    {
        m_StartThread = new Thread(&ServerNetwork::StartThread, this);
    }
}


////////////////////////////////////////////////////////////////////////////////


void ServerNetwork::StartThread()
{
    // Currently implemented only for Windows ...

    WSADATA wsaData;

    SOCKET ListenSendSocket = INVALID_SOCKET;
    SOCKET ListenRecvSocket = INVALID_SOCKET;

    struct addrinfo *result = NULL;
    struct addrinfo hints;

    // Initialize Winsock
    WSAStartup(MAKEWORD(2,2), &wsaData);

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
    getaddrinfo(NULL, m_SendPort.c_str(), &hints, &result);

    // Create a SOCKET for connecting to server
    ListenSendSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);

    // Setup the TCP listening socket
    bind( ListenSendSocket, result->ai_addr, (int)result->ai_addrlen);
    freeaddrinfo(result);

    listen(ListenSendSocket, SOMAXCONN);


    // Resolve the server address and port
    getaddrinfo(NULL, m_RecvPort.c_str(), &hints, &result);

    // Create a SOCKET for connecting to server
    ListenRecvSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);

    // Setup the TCP listening socket
    bind( ListenRecvSocket, result->ai_addr, (int)result->ai_addrlen);
    freeaddrinfo(result);

    listen(ListenRecvSocket, SOMAXCONN);

    typedef std::list<ServerSession> Sessions;
    Sessions sessions;

    while (true)
    {
        // Accept a client socket
        SOCKET ClientSendSocket = accept(ListenSendSocket, NULL, NULL);
        SOCKET ClientRecvSocket = accept(ListenRecvSocket, NULL, NULL);

        sessions.push_back( ServerSession( ClientSendSocket,
            ClientRecvSocket,
            m_RecvQueue,
            m_SendQueue,
            m_RecvQueueMutex,
            m_SendQueueMutex ) );

        sessions.back().Start();
    }
}


////////////////////////////////////////////////////////////////////////////////
